﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZYSocket.share;
using System.Reflection;
using Newtonsoft.Json;

namespace CSM.Lib.Protocol
{
	/// <summary>
	/// 协议字命令的基类型，主要表明协议字的类型
	/// </summary>
	public class ProtocolBase
	{
		public ProtocolBase(ProtocolWord type) { this.Type = type; }
		public ProtocolWord Type { get; set; }
	}

	/// <summary>
	/// 请求类协议字命令的基类型
	/// </summary>
	public class ProtocolReqBase : ProtocolBase
	{
		public ProtocolReqBase(ProtocolWord type) : base(type) { }
		public virtual ProtocolBase Response(UserInfo ui) { return null; }
	}

	/// <summary>
	/// 对请求类协议字做出响应的对应响应类协议字命令的基类型
	/// </summary>
	public class ProtocolRespBase : ProtocolBase
	{
		public ProtocolRespBase(ProtocolWord type) : base(type) { }
		public virtual ProtocolBase Response(object p) { return null; }
	}

	/// <summary>
	/// 协议字列表
	/// 如果不说明，所以协议序列都是由客户端发起，服务器端被动回应
	/// 以-Req结尾的协议字为协议请求命令，一般需要对方以相应的-Resp包回复
	/// 以-Resp结尾的协议字为对应协议字的回复协议字
	/// 每个协议字都会有对应的类对协议具体内容进行包装，并在Client和服务器间传递
	/// </summary>
	public enum ProtocolWord
	{
		/// <summary>
		/// 未知的命令字
		/// </summary>
		Unknown,
		/// <summary>
		/// 用户登录命令及回复
		/// </summary>
		UserLoginReq,
		UserLoginResp,

		/// <summary>
		/// 取得用户信息命令及回复
		/// </summary>
		UserInfoReq,
		UserInfoResp,

		/// <summary>
		/// 请求客户端初始化信息及回复
		/// </summary>
		SystemInfoReq,
		SystemInfoResp,
	}

	public static class Protocol
	{
		/// <summary>
		/// 协议报解析函数，返回解析出来的对象
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public static ProtocolBase[] Decoder(byte[] data, BuffList buffManager)
		{
			List<ProtocolBase> ret = new List<ProtocolBase>();

			// 对协议报数据进行crc校验
			if (CheckCRC(data) == false)
			{
				throw new CRCCheckException("协议buff CRC校验错误");
			}

			List<byte[]> datax;
			if (buffManager.InsertByteArray(data, 4, out datax))
			{
				if (datax != null)
				{
					foreach (byte[] mdata in datax)
					{
						ReadBytes read = new ReadBytes(data);
						int length;
						int cmd;
						Int16 ver;
						Int16 crc;
						int rsv;

						if (read.ReadInt32(out length) && read.ReadInt32(out cmd)
							&& read.ReadInt16(out ver) && read.ReadInt16(out crc)
							&& read.ReadInt32(out rsv) && length == read.Length)
						{
							byte[] buff;
							if (read.ReadByteArray(out buff))
							{
								try
								{
									string proto_name = "CSM.Lib.Protocol." + ((ProtocolWord)cmd).ToString();
									ProtocolBase obj = (ProtocolBase)Type.GetType(proto_name).Assembly.CreateInstance(proto_name);
									obj = (ProtocolBase)JsonConvert.DeserializeObject(Encoding.UTF8.GetString(buff), obj.GetType());
									ret.Add(obj);
								}
								catch (Exception ex)
								{
									throw ex;
								}
							}
							else
							{
								throw new InvalidDataException("不合法的协议包");
							}
						}
						else
						{
							throw new InvalidDataException("不合法的协议包头信息");
						}
					}
				}
			}

			return ret.ToArray();
		}

		/// <summary>
		/// 协议管理工具版本1.0
		/// </summary>
		static ushort ver = 0x0100;
	
		/// <summary>
		/// 
		/// </summary>
		/// <param name="cmd"></param>
		/// <param name="o"></param>
		/// <returns></returns>
		public static byte[] Encoder(ProtocolBase o)
		{
			BufferFormat buff = new BufferFormat((int)o.Type);

			buff.AddItem((Int16)ver);		//ver
			buff.AddItem((Int16)0x0000);	//crc
			buff.AddItem((int)0x00000000);	//reserve
			buff.AddItem(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(o)));
			byte[] ret = buff.Finish();

			UInt16 crc = CalcCRC(ret);
			ret[11] = (byte)(crc & 0xff);
			ret[12] = (byte)((crc >> 8) & 0xff);

			return ret;
		}

		/// <summary>
		/// 对data数据进行crc校验
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		private static bool CheckCRC(byte[] data)
		{
			UInt16 crc = (UInt16)(data[11] + (data[12] << 8));

			data[11] = 0;
			data[12] = 0;
			UInt16 crc1 = CalcCRC(data);

			return crc1 == crc;
		}

		/// <summary>
		/// 计算data的crc值
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		private static ushort CalcCRC(byte[] data)
		{
			UInt16 crc = 0;

			//计算checksum
			foreach (byte b in data)
			{
				crc = (UInt16)(crc ^ b);
			}

			return crc;
		}
	}

	/// <summary>
	/// 协议报crc校验错误异常
	/// </summary>
	public class CRCCheckException : Exception
	{
		public CRCCheckException() : base() { }
		public CRCCheckException(string msg) : base(msg) { }
	}

	/// <summary>
	/// 不认识的协议报类型异常
	/// </summary>
	public class UnknownTypeException : Exception
	{
		public UnknownTypeException() : base() { }
		public UnknownTypeException(string msg) : base(msg) { }
	}

	/// <summary>
	/// 不合法的协议报数据异常，通常是在解析协议数据过程中抛出
	/// </summary>
	public class InvalidDataException : Exception
	{
		public InvalidDataException() : base() { }
		public InvalidDataException(string msg) : base(msg) { }
	}

}
